namespace ScrumSprintMonitor.Modules.BuildMonitor.ViewModels
{
	#region #using Directives

	using System;
	using System.Globalization;
	using System.Threading;

	using Converters;

	using Infrastructure;

	using Microsoft.Practices.ServiceLocation;

	using Properties;

	#endregion

	public class BuildStatusDetailsViewModel : BuildViewModelBase,
	                                           IBuildStatusDetailsViewModel
	{
		private readonly ITeamMemberInfoProvider teamMemberInfoProvider;

		static BuildStatusDetailsViewModel()
		{
			var dependsOn = Register<BuildStatusDetailsViewModel>();

			dependsOn.Call(me => me.OnPropertyChanged("LastBuild")).OnChanged(me => me.ReportableData.LastBuild);
			dependsOn.Call(me => me.Exception = (me.LastBuild != null ? me.LastBuild.Exception : null)).OnChanged(me => me.LastBuild.Exception);
			dependsOn.Call(me => me.OnPropertyChanged("LastBuildNumber")).OnChanged(me => me.LastBuild.Number);
			dependsOn.Call(me => me.OnPropertyChanged("LastBuildFinishTime")).OnChanged(me => me.LastBuild.FinishTime);
			dependsOn.Call(me => me.OnPropertyChanged("BuildStatus")).OnChanged(me => me.LastBuild.Status);
			dependsOn.Call(me => me.OnPropertyChanged("RequestedFor")).OnChanged(me => me.LastBuild.RequestedFor);

			dependsOn.Call(me => me.OnPropertyChanged("HasException")).OnChanged(me => me.Exception);
			dependsOn.Call(me => me.OnPropertyChanged("BuildStatusText")).OnChanged(me => me.LastBuildFinishTime).OnChanged(me => me.BuildStatus);
		}

		public BuildStatusDetailsViewModel(ITeamMemberInfoProvider teamMemberInfoProvider, IServiceLocator serviceLocator)
			: base(serviceLocator)
		{
			if (teamMemberInfoProvider == null)
			{
				throw new ArgumentNullException("teamMemberInfoProvider");
			}

			this.teamMemberInfoProvider = teamMemberInfoProvider;

			if (SyncContext != null)
			{
				this.timer = new Timer(OnTimer, null, 60000, 60000);
			}
		}

		#region Private Fields

		private readonly Timer timer;

		private Exception exception;

		#endregion

		#region Private Methods

		protected override void EnsureConnected(bool throwException)
		{
			try
			{
				base.EnsureConnected(throwException);
			}
			catch (Exception e)
			{
				Exception = e;

				if (throwException)
				{
					throw;
				}
			}
		}

		private void OnTimer(object state)
		{
			OnPropertyChanged("BuildStatusText"); // Force relative date to update
		}

		#endregion

		public Exception Exception
		{
			get
			{
				GuardDisposed();

				if (this.exception == null)
				{
					EnsureConnected(false);
				}

				return this.exception;
			}
			private set
			{
				if (value != this.exception)
				{
					this.exception = value;

					OnPropertyChanged("Exception");
				}
			}
		}

		public bool HasException
		{
			get { return Exception != null; }
		}

		#region IBuildStatusDetailsViewModel Members

		public BuildStatus BuildStatus
		{
			get
			{
				EnsureConnected();
				return (LastBuild != null ? LastBuild.Status : BuildStatus.NotSetUp);
			}
		}

		public string LastBuildNumber
		{
			get
			{
				EnsureConnected();
				return (LastBuild != null ? LastBuild.Number : string.Empty);
			}
		}

		public DateTime LastBuildFinishTime
		{
			get
			{
				EnsureConnected();
				return (LastBuild != null ? LastBuild.FinishTime : DateTime.MinValue);
			}
		}

		public string BuildStatusText
		{
			get
			{
				string format = string.Empty;
				string timeSpan = (string) new TimeSpanConverter().Convert(LastBuildFinishTime, typeof(string), null, CultureInfo.CurrentUICulture);

				switch (BuildStatus)
				{
					case BuildStatus.NotSetUp:
						format = Resources.BuildStatusFormat_NotSetUp;
						break;
					case BuildStatus.Failed:
						format = Resources.BuildStatusFormat_Failed;
						break;
					case BuildStatus.NotStarted:
						format = Resources.BuildStatusFormat_NotStarted;
						break;
					case BuildStatus.InProgress:
						format = Resources.BuildStatusFormat_InProgress;
						break;
					case BuildStatus.PartiallySucceeded:
						format = Resources.BuildStatusFormat_PartiallySucceeded;
						break;
					case BuildStatus.Stopped:
						format = Resources.BuildStatusFormat_Stopped;
						break;
					case BuildStatus.Succeeded:
						format = Resources.BuildStatusFormat_Succeeded;
						break;
				}

				return string.Format(format, timeSpan);
			}
		}

		public string RequestedFor
		{
			get
			{
				EnsureConnected();

				if (LastBuild != null && !string.IsNullOrEmpty(LastBuild.RequestedFor))
				{
					var teamMember = this.teamMemberInfoProvider.GetTeamMemberInformation(LastBuild.RequestedFor);

					if (teamMember != null)
					{
						return teamMember.DisplayAlias;
					}

					return LastBuild.RequestedFor;
				}

				return string.Empty;
			}
		}

		#endregion

		#region Implementation of IDisposable

		protected override void Dispose(bool disposing)
		{
			base.Dispose(disposing);

			if (disposing)
			{
				if (this.timer != null)
				{
					this.timer.Dispose();
				}
			}
		}

		#endregion
	}
}